package com.swak.reactivex.transport.codec;

import com.swak.reactivex.transport.Channel;
import com.swak.reactivex.transport.Codec;
import com.swak.reactivex.transport.Message;
import com.swak.reactivex.transport.exception.CodecException;
import com.swak.reactivex.transport.exception.ExceedPayloadLimitException;
import com.swak.reactivex.transport.exception.ExchangeException.ExchangeMethod;
import com.swak.registry.URL;
import com.swak.spi.SPI;

import io.netty.buffer.ByteBuf;

/**
 * ExchangeCodec.
 *  
 * @author 618lf
 */
@SPI("ExchangeCodec")
public class ExchangeCodec implements Codec {

	private final MessageCodec codec;

	// magic header.
	public static final short MAGIC = (short) 0xbabe;

	public ExchangeCodec(URL url) {
		this.codec = new MessageCodec(MAGIC, url);
	}

	@Override
	public boolean support(Object message) {
		return message instanceof Message;
	}

	@Override
	public void encode(Channel channel, ByteBuf buffer, Object data) throws CodecException {
		try {

			Message message = (Message) data;

			// 编码
			this.codec.encode(buffer, message);

			// 校验总体的数据量不能超過最大的限量
			ExceedPayloadLimitException limitException = null;
			if ((limitException = Codec.checkPayloadQuietly(channel, message.getBodyLen())) != null) {

				// 直接抛出此异常
				// 抛出异常是要让发送端知道有异常产生
				throw limitException;
			}

		} catch (Throwable t) {

			// 清除缓冲区
			buffer.clear();

			// 返回
			throw new CodecException(ExchangeMethod.Write, data, t);
		}
	}

	@Override
	public Object decode(Channel channel, ByteBuf buffer) throws CodecException {

		// 解析到的数据
		Message message = null;
		try {

			// decode
			Object result = this.codec.decode(buffer);
			if (result == null || !(result instanceof Message)) {
				return result;
			}

			// decoded message
			message = (Message) result;

			// 校验总体的数据量不能超過最大的限量
			ExceedPayloadLimitException limitException = null;
			if ((limitException = Codec.checkPayloadQuietly(channel, message.getBodyLen())) != null) {

				// 需要回复数据给对端
				if (message.isResponse()) {
					Message r = Message.forResponse(message).setStatus(Message.BAD_RESPONSE);
					r.setError(limitException);
					return r;
				}

				// 其他的情况不需要处理，直接抛出此异常
				throw limitException;
			}

			// 返回结果
			return message;
		} catch (Throwable t) {
			throw new CodecException(ExchangeMethod.Read, message, t);
		}
	}
}
